#define _CRT_SECURE_NO_WARNINGS 1


		《 Linux_16_优先级 》

			《 优先级 》

1.什么是优先级：
指定进程获取某种资源(一般是CPU)的先后顺序

task_struct进程控制块 -> struct->内部字段->int prio =  ?
Linux中优先级数字越小，优先级越高
 < 优先级 vs 权限 >
优先级：已经有权限了，考虑获取资源的顺序
权限  ：能不能

2.为什么要有优先级：
进程访问的资源（CPU）始终都是有限的系统中进程大部分情况都是有较多的。

操作系统关于调度和优先级的原则: 
分时(大部分)操作系统(基于时间片来进行调度的)，要保证基本的公平。
如果进程因长时间不被调度，就造成了饥饿问题。


		《 查看进程 优先级 》
[a@192 ~]$ ps - l		//当前窗口
F S   UID    PID   PPID  C 【PRI】  【NI】   ADDR SZ WCHAN  TTY          TIME CMD
0 S  1000   3404   2913  0  [ 80 ]   [ 0 ] - 29214 do_wai pts / 1    00:00 : 00 bash
0 R  1000   3450   3404  0  [ 80 ]   [ 0 ] - 38331 - pts / 1    00 : 00 : 00 ps
[a@192 ~]$ ps - al	// al 全部以详细的信息显示
F S   UID    PID   PPID  C PRI  NI ADDR SZ WCHAN  TTY          TIME CMD
0 S  1000   3400   2921  0  80   0 - 1054 hrtime pts / 0    00 : 00 : 00 myprocess
0 R  1000   3465   3404  0  80   0 - 38331 - pts / 1    00 : 00 : 00 ps

		< 修改进程优先级 >
PRI ：进程优先级 代表这个进程可被执行的优先级，其值越小越早被执行
NI  ：进程优先级 的修正数据，nice 值，nice 的取值范围： -20~19
新优先级 = 优先级 + nice  达到对于进程优先级动态修改的过程。
UID   ：代表执行者的身份PID:代表这个进程的代号
PPID  ：代表这个进程是由哪个进程发展衍生而来的，亦即父进程的代号


		《 调整优先级 》

		< top >

每次调整优先级，都会从默认的80 开始调整
top 类似于任务管理器
top 命令查看系统的运行状态, 包括负载, 内存使用(交换分区), CPU使用、当前运行的线程, 进程等信息

用top命令更改已存在进程的nice:
进入top后按 "r" ->输入进程PID -> 输入nice值

 输入 r 后：
PID to renice[default pid = 2026] 输入要调整的 PID 3400
Renice PID 3400 to value 10		//把3400 的优先级 +10(nice值)， nice 的取值范围： -20~19
输入 q  退出
0 S  1000   3773   2921  0  90  10 - 1054 hrtime pts / 0 * / 00:00 : 00 myprocess

 普通用户只能 +nice 值， root用户才能 + - nice 值
[a@192 ~]$ ps - al
F S   UID    PID   PPID  C PRI  NI ADDR SZ WCHAN  TTY          TIME CMD
0 S  1000   3773   2921  0  99  19 - 1054 hrtime pts / 0  */  00:00 : 00 myprocess

 切换 root ： nice值输入 -10 ： PID并不是从99 -10，而是从 默认值 80 -10
[root@192 ~]# ps - al
F S   UID    PID   PPID  C PRI  NI ADDR SZ WCHAN  TTY          TIME CMD
0 S  1000   3773   2921  0  70 - 10 - 1054 hrtime pts / 0    00:00 : 00 myprocess

 每次调整优先级，都会从默认的80 开始调整。+ - 都是。
prio 最终优先级
default_prio = 80 默认优先级 
nice = [-20 ~ 19] 可修改优先级值 
prio = default_prio + nice 得到 最终优先级 [60 ~ 99]


		< 并行/并发 >
其他概念
·竞争性 : 系统进程数目众多，而CPU资源只有少量，甚至1个，所以进程之间是具有竞争属性的。
           为了高效完成任务，更合理竞争相关资源，便具有了优先级
·独立性 : 多进程运行，需要独享各种资源，多进程运行期间互不干扰
·并行   : 多个进程在多个CPU下分别，同时进行运行，这称之为并行
·并发   : 多个进程在一个CPU下采用进程切换的方式，在一段时间之内，让多个进程都得以推进，称之为并发


————————————————————————————————————————————————————————————


————————————————————————————————————————————————————————————


		 < main 函数带参 >

#include <stdio.h>
#include <unistd.h>

int main(int argc, char* argv[])        //argc 表示命令行中传递给程序的参数总数（包括程序名本身）
{                                       //argv[] 命令行参数表：是字符指针数组，存储了每个参数的具体值。
	for (int i = 0; i < argc; i++)
	{
		printf("argv[%d] -> %s\n", i, argv[i]);
	}
 return 0;
}

  程序的路径+名称↓      ↓和该进程匹配的选项：[命令行字符串]    
("./myprocess -a -b -c -d"字符串中间的 空格 == '\0'为分隔)
[a@192 ~]$ ./myprocess -a -b -c -d
argv[0] -> ./myprocess
argv[1] -> -a
argv[2] -> -b
argv[3] -> -c
argv[4] -> -d


		< 验证以 NULL 结尾 >

int main(int argc, char* argv[])
{
	for (int i = 0; argv[i]; i++)               //argv[i] 以 NULL 结尾(0为假 不进入循环)
	{
		printf("argv[%d] -> %s\n", i, argv[i]);
	}
}


————————————————————————————————————————————————————————————


//       《 命令行参数 》
//《 同一程序 传不同选项 实现不同功能 》

为什么要有命令行参数？
本质 : 命令行参数本质是交给我们程序的不同的选型，
用来定制不同的程序功能。命令中会携带很多的选项。

#include <stdio.h>
#include <unistd.h>
#include <string.h>
int main(int argc, char* argv[])
{
	if (argc != 2)
	{
		printf("Usage: %s -[a,b,c,d]\n", argv[0]);
		return 1;
	}

	if (strcmp(argv[1], "-a") == 0)
	{
		printf("this is function1\n");
	}
	else if (strcmp(argv[1], "-b") == 0)
	{
		printf("this is function2\n");
	}
	else if (strcmp(argv[1], "-c") == 0)
	{
		printf("this is function3\n");
	}
	else if (strcmp(argv[1], "-d") == 0)
	{
		printf("this is function4\n");
	}
	else
	{
		printf("no this function!!\n");
	}

	return 0;
}


[a@192 ~]$  ./myprocessUsage: ./myprocess -[a, b, c, d]    // 默认是输入给父进程bash的!! bash命令行解释器
[a@192 ~]$  ./myprocess - a
this is function1

[a@192 ~]$  ./myprocess - b
this is function2
[a@192 ~]$  ./myprocess - c
this is function3
[a@192 ~]$  ./myprocess - d
this is function4

[a@192 ~]$  ./myprocess - e
no this function!!
[a@192 ~]$


————————————————————————————————————————————————————————————


————————————————————————————————————————————————————————————


父进程的数据，默认能被子进程看到并访问的：

#include <stdio.h>
#include <unistd.h>
#include <string.h>

int g_val = 100000; 

int main()
{
	printf("I am father process! pid: %d, ppid: %d, g_val: %d\n", getpid(), getppid(), g_val);
	sleep(5);

	pid_t id = fork();
	if (id == 0)
	{
		// child 子进程
		while(1) 
		{
			printf("I am child process! pid: %d, ppid: %d, g_val: %d\n", getpid(), getppid(), g_val);
			sleep(1);
		}
	}
	else 
	{
		// father
		while(1) 
		{
			printf("I am father process! pid: %d, ppid: %d, g_val: %d\n", getpid(), getppid(), g_val);
			sleep(1);
		}
	}
	return 0;
}

[a@192 ~]$  ./myprocess
I am father process! pid : 27393, ppid : 10069, g_val : 100000
I am father process! pid : 27393, ppid : 10069, g_val : 100000
I am child  process! pid : 27417, ppid : 27393, g_val : 100000
I am father process! pid : 27393, ppid : 10069, g_val : 100000
I am child  process! pid : 27417, ppid : 27393, g_val : 100000
父进程的数据，默认能被子进程看到并访问

[a@192 ~]$ ps ajx | grep 10069 
10064 10069 10069 10042 pts/2 28182 S 1003 0:00 bash
命令行中启动的程序，都会变成进程，其实都是bash的子进程。


————————————————————————————————————————————————————————————


————————————————————————————————————————————————————————————


			《 环境变量 》

PATH:环境变量 (指令的操作路径保存在其中，which 搜索的路径就是在环境变量中搜索的)
打印环境变量的内容: $PATH

 1.直接看现象
Linux中，存在一些全局的设置，表明，告诉命令行解释器，应该去那些路径下去寻找可执行程序

[a@192 d]$ echo $PATH
 usr / local / sbin: / usr / local / bin : / sbin : / bin : / usr / sbin : / usr / bin : / root / bin
[a@192 d]$

bash 在执行命令的时候，需要先找到命令，因为未来要加载!
系统中很多的配置，在我们登录Linux系统的时候，已经被加载到了bash进程中(内存)


也可以像系统命令一样，不带 ./ 路径，只需要拷贝到对应系统文件中
[a@192 d]$ sudo cp myprocess /usr/bin/  (把自己写的可执行程序拷贝到系统指令路径下 == 安装了我们自己的可执行程序)
[sudo] password for whb:

[a@192 d] $ myprocess		//像系统命令一样不带 ./ 路径
l am father process, pid : 399, ppid : 10069, g_val : 100000
Usage : myprocess - [a, b, c, d]

这就是 Linux 系统中的安装和卸载
[a@192 d] $ sudo rm / usr / bin / myprocess		//删除这个文件就是卸载。


		< $PATH >
内存级：覆盖式，自己添加的能跑了，但是其他环境变量可能不能跑了。不推荐，避免污染命令池。
[a@192 d] $ PATH = / home / whb / 111 / code / lesson14			
内存级：添加式，不影响 其他环境变量，推荐！
[a@192 d] $ PATH = $PATH: / home / whb / 111 / code / lesson14	

$PATH 是 Linux 当中搜索可执行程序的默认路径 ，也是 which 搜索到的程序路径。
[a@192 d] $ which myprocess 

如何改为永久的呢？
最开始的环境变量不是在内存中，而是在系统的对应的配置文件中
这个 配置文件，在哪里 ? ? ?
环境变量默认是在【配置文件中】!!!
【 .bash profile 】	//当前目录的配置文件 (把我的程序路径加入到配置文件中 PATH=$PATH:$...     :我的路径 )
【 .bashrc 】         //bashrc是home目录下的一个shell文件,用于储存用户的个性化设置。并根据内容定制当前bash的配置和环境。
【/etc/bashrc】		//系统的配置文件


————————————————————————————————————————————————————————————


————————————————————————————————————————————————————————————




		《 环境变量 》

		< env >
env 【查看所有的环境变量】

		< echo / echo $ >
echo命令 echo命令用于在终端设备上输出字符串或变量提取后的值, 语法格式为:“echo[字符串][$变量]”。
echo $变量, 其中$符号意思是提取变量的实际值, 如 : 注 : 变量需大写
 
常见的环境变量：
PHTH        指定命令的搜索路径
SSH_CLIENT  :=123.13.72.100  24843  22 (登录的客户端，进程号， 网络端口)
SHELL       :当前Shell,它的值通常是/bin/bash。

【查看单个环境变量】：
echo $HOME 当前用户所在的家目录 
echo $PWD  当前所在路径的环境变量
echo $HISTSIZE 历史命令记录: 1000，Linux会记录 1000 条历史命令



【自己定义一个环境变量】：
		< export >
语法： 
export name=value
export 环境变量的名字=环境变量的内容
示例：内存级的， 永久级要到配置文件中更改。
export THIS_IS_MY_ENV= hello 
env | grep hello
结果：THIS_IS_MY_ENV = hello

		< unset >
取消环境变量：
unset NAME
unset 环境变量名
unset THIS_IS_MY_ENV

		《 本地变量 》
hello=1234
env | grep hello // 查找环境变量是没有的
_
echo $hello		// 没有导到环境变量中，却依旧存在,本地变量
1234

————————————————————————————————————————————————————————————


		< 通过程序获取环境变量 >
环境变量默认，可以被子进程拿到的。
环境变量默认在 bush 内部

#include <stdio.h>
#include <unistd.h>
#include <string.h>

int main()
{
	extern char** environ;	//使用外部的定义 (注意: 这里是二级指针** )
	for (int i = 0; environ[i]; i++)
	{
		printf("env[%d]->%s\n", i, environ[i]);
	}
	return 0;
}


————————————————————————————————————————————————————————————

获取环境变量方法1：
extern char** environ;
通过 main 函数参数获取环境变量

环境变量在 bush 内部是如何组织的呢？
char *env[]
[  char*  ] ==> "PATH=/usr/bin/a/b/c..."
[ "PATH=/usr/bin/a/b/c..." ]

char *env[]
[  char*  ] env[0]=MANPATH=/opt/rh/...
[  char*  ] env[1]=XDG_ID=...
[  ...    ] env[3]=HOSTNAME=hello ...
[  NULL   ]	// 最后以 NULL 结尾

bash进程启动的时候，默认会给我子进程形成 2张表:
1. argv[]命令行参数表。 从用户输入命令行来。
2. env []环境变量  表。 从OS的配置文件获取。
bash通过各种方式交给子进程!!!

————————————————————————————————————————————————————————————

//argc 表示: 命令行中传递给程序的参数总数（包括程序名本身）
//argv[] 命令行参数表：是字符指针数组，存储了每个参数的具体值。
//env[] 环境变量表

main 函数带参传递环境变量：
int main(int argc, char* argv[], char* env[])	// main 函数最多传 3个参数
{
	for (int i = 0; env[i]; i++)
	{
		printf("env[%d]->%s\n", i, env[i]);
	}
	return 0;
}

————————————————————————————————————————————————————————————

环境变量具有系统级的全局属性，因为环境变量本身会被子进程继承下去

 
获取环境变量方法2：
  getenv("path")
 
#include <stdlib.h>
man getenv 
char* getenv(const char* name);	//直接根据环境变量名拿到它的环境变量内容。

man putenv
int putenv(char* string);	//...


#include <stdlib.h>
int main(int argc, char* argv[], char* env[])
{
	char* path = getenv("PATH");
	if (path == NULL)
		return 1;
	printf("path:%s\n", path); //获取到了，打印环境变量的内容。
	
	return 0;
}

Linux 80% 的命令都是 bash 创建的子进程执行的，
但是也有部分命令 由 bash 自己执行，内建命令,例如：export， echo ... 

本地变量只在本bash内部有效，无法被子进程继承下去。
导成环境变量，此时才能够被获取
 HELLO=333333
echo $HELLO
333333		//能查到但是，不是环境变量
env | grep HELLO 
 _			//没有环境变量
export HELLO	//把 HELLO 加入环境变量
333333		//生成环境变量

unset HELLO	//删除环境变量


————————————————————————————————————————————————————————————


————————————————————————————————————————————————————————————
